/**
 * @Aurhor 把手给我
 * @Date 2022/9/6 20:01
 * @Version 1.0
 * websoket处理类，类似于servlet
 **/
package com.ft.websocket.service;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ft.dao.UserDao;
import com.ft.domain.Message;
import com.ft.service.IUserService;
import com.ft.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@CrossOrigin
@Component
@ServerEndpoint("/chat/{userid}")
public class ChatEndpoint {
    //静态变量，用来记录当前在线连接数。
    public static Long onlineCount = Long.valueOf (0);
    //用来存储每个客服端对象对应发ChatEndpoint对象，可以通过id,或者用户名区分
    public static Map<String, ChatEndpoint> onlineUsers = new ConcurrentHashMap<> ();
    //声明Session对象，通过这个对象可以发送消息给指定用户
    private Session session;
    //用户id
    private String userId = "";
    @Autowired
    UserDao userdao;
    public static IUserService userService;
    @Autowired
    public void setUserService(IUserService userService){
        ChatEndpoint.userService = userService;
    }

    @OnOpen
    //建立链接时被调用
    public synchronized void OnOpen(Session session1, @PathParam("userid") String userid) throws Exception {
        //将局部的session对象赋值给成员session
        this.session = session1;
        this.userId = userid;
        //判断是否是重连
        if(onlineUsers.containsKey(userid)){
            onlineUsers.remove(userid);
            //连接建立成功后，将该对象存入容器中
            onlineUsers.put (userId, this);
            System.out.println ("重连的用户"+userid);
        }else {
            //连接建立成功后，将该对象存入容器中
            onlineUsers.put (userId, this);
            addOnlineCount();
            System.out.println(userid+"上线了");
        }
        //创建消息对象
        Message message = new Message ();
        message.setSendUser (userId);
        message.setIsSystem (4);
        message.setReceiveUser(userId);
        message.setMessagecontent (userId + "链接成功了");
        //将消息推送给该用户
        try {
            sendMessageToUser (message);
        } catch (IOException e) {
            e.printStackTrace ();
        }
    }

    @OnMessage
    //接收到客户端发送的消息时被调用
    public synchronized void OnMessage(String message, Session session) throws Exception {
        //将接收的信息转换成自己定义的message类对象
        //1.创建json对象,转换成message消息对象
        ObjectMapper obj = new ObjectMapper ();
        Message message1 = obj.readValue (message, Message.class);
        if(message1.getIsSystem()  != 3){
            System.out.println("接收到客户端发送的消息"+message1.getMessagecontent());
        }
        //判断是否是心跳检查
        if (message1.getIsSystem () == 3 && message1.getMessagecontent ().equals ("ping")) {
            palpitateMessage (message1);
        } else {
            //发送消息给用户
            sendMessageToUser (message1);
        }
    }

    @OnClose
    //连接关闭时被调用
    public synchronized void OnClose(Session session, @PathParam("userid") String userid) {
        if (onlineUsers.containsKey (userId)) {
            //移除用户
            onlineUsers.remove (userId);
            //在线人数减1
            ChatEndpoint.subOnlineCount ();
        }
        System.out.println (userId + "关闭了");
    }
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println ("发生错误" + error);
        error.printStackTrace ();
    }

    /**
     * 推送消息给所有用户,系统消息
     *
     * @param message 推送的消息
     */
    public synchronized static int systemMessage(Message message) {
        //每推送一个用户加1
        int total = 0;
        //总人数
        Long usernum = ChatEndpoint.onlineCount;
        Set<String> names = onlineUsers.keySet ();
        if (names.size () > 0) {
            for (String name : names) {
                ChatEndpoint chatEndpoint = onlineUsers.get (name);
                try {
                    chatEndpoint.session.getBasicRemote ().sendText (JSONObject.toJSONString(message));
                } catch (IOException e) {
                    e.printStackTrace ();
                }
            }
        }
        if(total == usernum){
            return  1;
        }else {
            return 0;
        }
    }

    /**
     * 心跳检查服务端返回消息
     */
    public void palpitateMessage(Message message) throws IOException {
        session.getBasicRemote ().sendText (JSONObject.toJSONString(message));
    }

    /**
     * 系统推送给用户的消息，用户接单，完成订单。
     * @param message
     */
    public static synchronized int systemSendToUserOne(Message message) throws IOException, IllegalAccessException {
        //判断要推送的用户是否在线
        boolean contains = onlineUsers.containsKey(message.getReceiveUser ());
        if (contains) {
            //发送给其他用户信息
            ChatEndpoint chatEndpoint = onlineUsers.get (message.getReceiveUser ());
            chatEndpoint.session.getBasicRemote ().sendText (JSONObject.toJSONString(message));
            return 1;
        }else {
            //创建离线消息
            int i = userService.addOfflineUsermessage(message);
            if(i == 1) {
                return 1;
            }else {
                return 0;
            }
        }
    }

    /**
     * 订单通知相关
     * @param receiveUser 接单用户
     * @param username 接单用户名
     * @return
     */
    public static synchronized  int orderMessage(String receiveUser, String username,String msg) throws IOException, IllegalAccessException {
        //封装发送的消息
        Message message = new Message();
        //设置订单通知消息
        message.setIsSystem(6);
        //设置接收信息的用户
        message.setReceiveUser(receiveUser);
        message.setMessagecontent(msg);
        //设置消息时间
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = sdf1.format(new Date());
        message.setCreateTime(date);
        int T = systemSendToUserOne(message);
        if(T == 1){
            return 1;
        }
        return 0;
    }


    /**
     * 单个推送
     *
     * @param message
     * @throws IOException
     */
    private synchronized void sendMessageToUser(Message message) throws Exception{
        //判断要推送的用户是否在线
        boolean contains = onlineUsers.containsKey(message.getReceiveUser ());
        if (contains) {
            if(message.getIsSystem() != 3) {
                System.out.println("接收的用户在线" +message.getReceiveUser());
            }
            //发送给其他用户信息
            ChatEndpoint chatEndpoint = onlineUsers.get (message.getReceiveUser ());
            chatEndpoint.session.getBasicRemote ().sendText (JSONObject.toJSONString(message));
            //封装校验消息,给发送用户
            Message T = new Message();
            T.setIsSystem(5);
            T.setMessagecontent("消息发送成功!");
            session.getBasicRemote().sendText(JSONObject.toJSONString(T));
        } else {
            //创建离线消息
            int i = userService.addOfflineUsermessage(message);
            if(i == 1) {
                //封装校验消息
                Message T = new Message();
                T.setIsSystem(5);
                T.setMessagecontent("消息发送成功!");
                session.getBasicRemote().sendText(JSONObject.toJSONString(T));
            }else {
                //封装校验消息
                Message T = new Message();
                T.setIsSystem(5);
                T.setMessagecontent("消息发送失败!");
                session.getBasicRemote().sendText(JSONObject.toJSONString(T));
            }
        }
    }

    //获取在线人数
    public static synchronized Long getOnlineCount() {
        return onlineCount;
    }

    //增加在线人数
    public static synchronized void addOnlineCount() {
        ChatEndpoint.onlineCount++;
    }

    //减少在线人数
    public static synchronized void subOnlineCount() {
        ChatEndpoint.onlineCount--;
    }
}